package siedler.GUI.gameElements;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import siedler.GUI.other.Coordinate;
import util.Tools;
import util.simpleIO.Out;

public class Pictures {
	
	//public static ResourcesEnum = siedler.gaming.Resources.ResourcesEnum;
	//public static enum ResourcesEnum = siedler.gaming
	
	public static final int TRANSPARENT = 0x00FFFFFF;
	
	public final static int nrOfFieldPictures = siedler.gaming.Resources.ResourcesEnum.values().length;
	public final static BufferedImage[] fieldPictures = new BufferedImage[nrOfFieldPictures];
	
	/**
	 * loads the pictures used in the game
	 */
	public static void initPictures(){
		fieldPictures[0] = getTransparentImage1("track.jpg");
	}
	
	/**
	 * Get transparent image with class Field and file
	 * @param file
	 * @return
	 */
	private static BufferedImage getTransparentImage1(String file){
		
		// --- load picture ---
		//
		BufferedImage pic = null;
		try {
			pic = ImageIO.read(new File(file));
		} 
		catch (IOException e) {
			e.printStackTrace();
		}
		
		// --- sizes ---
		//
		if(pic.getWidth() != pic.getHeight()) 
			System.err.println("> Warning: Image hight and width should be the same.");
		int x,y,size;
		size = (pic.getWidth() > pic.getHeight()) ? pic.getWidth() : pic.getHeight();	// size is the bigger one...
		x = pic.getWidth()/2;		// middle x
		y = pic.getHeight()/2;		// middle y
		
		// --- field for drawing mask ---
		//
		Field f = new Field(0);								// new field. ID not relevant
		f.initGraphics(new Coordinate(x,y), size);			// init position and size
		
		// --- make mask ---
		//
		BufferedImage mask;							
		mask = new BufferedImage(pic.getWidth(), pic.getHeight(), BufferedImage.TYPE_INT_ARGB);
		mask.createGraphics();								// make graphics for image
		Graphics2D g2 = (Graphics2D) mask.getGraphics();	// get graphics from image
		g2.setColor(Color.RED);								// paint in red
		//g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);	// Antialiasing
		f.paintHexagon(g2);									// paint mask
		g2.dispose();										// return unused memory
		
		return getTransparentImage2v1(pic, mask);
		
//		return getTransparentImage2v2(f.getHexagon(), pic, size);
	}
	
	/**
	 * Sets the outer color (left top) of the picture transparent.
	 * 
	 * @param pic
	 * @param mask	- black / red
	 * @return BufferedImage
	 */
	public static BufferedImage getTransparentImage2v1(BufferedImage pic, BufferedImage mask){
		
//		int cIn  = mask.getRGB(mask.getWidth()/2, mask.getHeight()/2);	// middle
//		int cOut = mask.getRGB(0, 0);									// left top corner
//		
//		Out.pl( "cIn  ... " + Tools.getBitString( cIn  ) );
//		Out.pl( "cOut ... " + Tools.getBitString( cOut ) );
		
		//int BLACK = Color.BLACK.getRGB() & TRANSPARENT;
		
		BufferedImage result = new BufferedImage(mask.getWidth(), mask.getHeight(), BufferedImage.TYPE_INT_ARGB);
		
		for(int y1=0; y1<pic.getHeight(); y1++){						// set outer color transparent
			//int cLast = BLACK;
			
			for(int x1=0; x1<pic.getWidth(); x1++){
				
				int cMask = mask.getRGB(x1,y1);					// Mask color (Black/Red)
				int cPic  = pic.getRGB(x1,y1) ;					// Picture Color
				
				int transperancyByte = cMask >>(2*8) & 0x0000FF;		// get 3rd byte (RED)
				int transperancy = transperancyByte<<(3*8) | TRANSPARENT;	// red in mask is transperancy
				
				int cNew = cPic & transperancy;
				
				result.setRGB(x1, y1, cNew);
				
//				if(transperancyByte>0 && transperancyByte<255)
//					Out.pl("Transperancy: " + transperancyByte);
			}
		}
		return result;	
	}
	
	
	/**
	 * get Image with transparency effects
	 * 
	 * @param points - x/y, filled, opaque shape
	 * @param pic - original picture
	 * @param size - max from x or y
	 * @return
	 */
	public static BufferedImage getTransparentImage2v2(int[][] points, BufferedImage pic, int size){
		
		float[][] mask = new float[size][size];
		
		// --- draw lines ---
		int len = points[0].length;
		for(int i=0; i<len; i++){
			
			int x1=points[0][i], y1=points[1][i];
			int x2=points[0][(i+1)%len], y2=points[1][(i+1)%len];
			
			drawLine(mask, x1, y1, x2, y2);
		}
		int pMax = points.length-1;
		drawLine(mask, points[0][pMax], points[1][pMax], points[0][0], points[1][0]);
		
		// --- fill mask ---
		fill(mask);
		
		// --- draw image ---
		return maskToImage(mask, pic);
		
		
//		for(int y1=0; y1<pic.getHeight(); y1++){						// set outer color transparent
//			for(int x1=0; x1<pic.getWidth(); x1++){
//				
//				int lim1, lim2;
//				lim1 = 
//				
//			}
//		}
	}
	
	/**
	 * Draws a line in the specified Mask. (antialiased)
	 * @param mask
	 * @param x1
	 * @param y1
	 * @param x2
	 * @param y2
	 */
	public static void drawLine(float[][] mask, int x1, int y1, int x2, int y2){
		
		int steps = (y2>y1) ? y2-y1 : y1-y2;			// positive integer
		
		int   yStep = (y2>y1) ? 1 : -1;					// 1 pixel y-step
		float xStep = (steps>0) ? (x2-x1)/steps : 0;	// float x-step
		
		for(int y=y1,x=x1; y<=y2; y+=yStep,x+=xStep){
			
			int x_a       = (int) x;			// x-coordinate 1
			int x_b       = x_a + 1;			// x-coordinate 2
			
			float trans_b = x - x_a;			// transparency 1
			float trans_a = 1 - trans_b;		// transparency 2
			
			mask[y][x_a] = trans_a;				// transparency mask
			mask[y][x_b] = trans_b;				// transparency mask
		}
		
	}
	
	/**
	 * Fills lines in mask. 
	 * @param mask
	 */
	private static void fill(float[][] mask){
		
		for(int y=0; y<mask.length; y++){		// for every line:
			
			int lim1=-1, lim2=-1;
			int xMax = mask[y].length-1;
			
			for(int x=0; x<=xMax; x++){				// left limit:
				if(mask[y][x]>0){
					lim1 = x+1;
					break;
				}
			}
			for(int x=xMax; x>=0; x--){				// right limit:
				if(mask[y][x]>0){
					lim2 = x-1;
					break;
				}
			}
			
			if(lim1>0 && lim2>0 && lim1<=xMax && lim2>=0 && lim1<=lim2){	// condition for correct and existing limits
				for(int x=lim1; x<=lim2; x++){								// fill line:
					mask[y][x] = 1f;
				}
			}
		}
	}
	
	/**
	 * Get transparency effects with 
	 * @param mask - float[][]
	 * @param pic - original picture
	 * @return BufferedImage
	 */
	private static BufferedImage maskToImage(float[][] mask, BufferedImage pic){
		
		BufferedImage result = new BufferedImage(mask[0].length, mask.length, BufferedImage.TYPE_INT_ARGB);
		
		// --- process every pixel ---
		for(int y=0; y<pic.getHeight(); y++){						
			for(int x=0; x<pic.getWidth(); x++){
				
				int transparencyByte = (int) (255 * mask[y][x] +0.5f);		// byte up to 255
				int transparency = transparencyByte<<(3*8) | TRANSPARENT;	// red in mask is transperancy
				
				int cNew = pic.getRGB(x,y) & transparency;			// new, transparent color
				result.setRGB(x, y, cNew);							//set new color
				
				if(transparencyByte>0)
					Out.p("O");
				else
					Out.p("_");
			}
			Out.pl();
		}
		
		return result;
	}
	
}
